package com.kate.mall.bff.wx.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import com.kate.mall.bff.wx.controller.form.CartAddForm;
import com.kate.mall.bff.wx.controller.form.CartCheckoutForm;
import com.kate.mall.bff.wx.dto.CartDTO;
import com.kate.mall.bff.wx.feign.*;
import com.kate.mall.bff.wx.service.CartService;
import com.kate.mall.bff.wx.vo.goods.GoodsInfoVo;
import com.kate.mall.bff.wx.vo.coupon.CouponVo;
import com.kate.mall.bff.wx.vo.promotion.GroupOnRulesVo;
import com.kate.mall.bff.wx.vo.ums.AddressVo;
import com.kate.mall.common.annotation.LoginUser;
import com.kate.mall.common.utils.JacksonUtil;
import com.kate.mall.common.utils.R;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.ResponseUtil;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: 用一句话描述
 * @Auther: 新梦想*陈超
 * @Date: 2021/8/16 21:40
 */
@RestController
@RequestMapping("/wx/cart")
@Slf4j
public class CartController {

    @Resource
    private CartService cartService;

    @Resource
    private ProductFeignClient goodsFeignClient;

    @Resource
    private UmsFeignClient addressFeignClient;

    @Resource
    private PromotionFeignClient groupOnFeignClient;

    @Resource
    private CouponFeignClient couponFeignClient;

    @Resource
    private MallFeignClient systemConfigFeignClient;

    /**
     * 用户购物车信息
     * @param userId 用户ID
     * @return 用户购物车信息
     */
    @GetMapping("index")
    @ApiImplicitParams({@ApiImplicitParam(name="userId",value = "X-Litemall-Token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",paramType = "header",required = true,dataType = "String")})
    public Object index(@LoginUser Integer userId) {
//        userId =4;
        if (userId == null) {
            return R.unlogin();
        }

        List<CartDTO> list = cartService.queryByUid(userId);
        List<CartDTO> cartList = new ArrayList<>();
        // TODO
        // 如果系统检查商品已删除或已下架，则系统自动删除。
        // 更好的效果应该是告知用户商品失效，允许用户点击按钮来清除失效商品。
        for (CartDTO cart : list) {
            //@kate  qbc的查询效率很低，改进为使用表连接，一条sql语句比多条
            R goodsR =goodsFeignClient.detail(cart.getGoodsId());
            GoodsInfoVo goodsDetailVo = MapUtil.get((Map) goodsR, "cart", GoodsInfoVo.class);
            if (goodsDetailVo == null || !goodsDetailVo.getIsOnSale()) {
                //@kate 删除效率低 可以为 where 拼接多个id 一次删除多个
                cartService.deleteById(cart.getId());
                log.debug("系统自动删除失效购物车商品 goodsId={},productId={}" , cart.getGoodsId(),cart.getProductId());
            }
            else{
                cartList.add(cart);
            }
        }

        Integer goodsCount = 0;
        BigDecimal goodsAmount = new BigDecimal(0.00);
        Integer checkedGoodsCount = 0;
        BigDecimal checkedGoodsAmount = new BigDecimal(0.00);
        for (CartDTO cart : cartList) {
            goodsCount += cart.getNumber();
            goodsAmount = goodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            if (cart.getChecked()) {
                checkedGoodsCount += cart.getNumber();
                checkedGoodsAmount = checkedGoodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            }
        }
        Map<String, Object> cartTotal = new HashMap<>();
        cartTotal.put("goodsCount", goodsCount);
        cartTotal.put("goodsAmount", goodsAmount);
        cartTotal.put("checkedGoodsCount", checkedGoodsCount);
        cartTotal.put("checkedGoodsAmount", checkedGoodsAmount);

        Map<String, Object> result = new HashMap<>();
        result.put("cartList", cartList);
        result.put("cartTotal", cartTotal);

        return R.ok(result);
    }
    /**
     * 立即购买
     * <p>
     * 和add方法的区别在于：
     * 1. 如果购物车内已经存在购物车货品，前者的逻辑是数量添加，这里的逻辑是 数量覆盖
     * 2. 添加成功以后，前者的逻辑是返回当前购物车商品数量，这里的逻辑是返回对应购物车项的ID
     *
     * @param userId      用户ID
     * @param cartAddForm 购物车商品信息， { goodsId: xxx, productId: xxx, number: xxx }
     * @return 立即购买操作结果
     */
    @PostMapping("/fastadd")
    public R fastAdd(@LoginUser Integer userId, @RequestBody CartAddForm cartAddForm) {
//        userId= 4;
        return cartService.save(userId, cartAddForm);
    }
    /**
     * 购物车下单
     *
     * @param userId    用户ID
     * @param cartCheckoutForm
     *  cartId    购物车商品ID：
     *              如果购物车商品ID是空，则下单当前用户所有购物车商品；
     *              如果购物车商品ID非空，则只下单当前购物车商品。
     *  addressId 收货地址ID：
     *               如果收货地址ID是空，则查询当前用户的默认地址。
     *  couponId  优惠券ID：
     *               如果优惠券ID是空，则自动选择合适的优惠券。
     * @return 购物车操作结果
     */
    @PostMapping("checkout")
    @ApiImplicitParams({@ApiImplicitParam(name="userId",value = "X-Litemall-Token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",paramType = "header",required = true,dataType = "String")})
    public Object checkout(@LoginUser Integer userId,
                           @RequestBody CartCheckoutForm cartCheckoutForm) {
//        userId = 4;
        if (userId == null) {
            return R.unlogin();
        }
        // 收货地址
        R checkedAddressR = null;
        AddressVo addressVo = null;
        Integer addressId = cartCheckoutForm.getAddressId();
        Integer grouponRulesId  =cartCheckoutForm.getGrouponRulesId();
        Integer cartId=cartCheckoutForm.getCartId();
        Integer couponId = cartCheckoutForm.getCouponId();
        Integer userCouponId = cartCheckoutForm.getUserCouponId();
        if (addressId== null || addressId.equals(0)) {
            checkedAddressR = addressFeignClient.findDefault(userId,true);
            List<Map> checkedAddressMap = MapUtil.get((Map)checkedAddressR.get("page"),"list",List.class);

            if(checkedAddressMap.size()>0){
                addressVo = BeanUtil.mapToBean(checkedAddressMap.get(0), AddressVo.class,false);
            }
            // 如果仍然没有地址，则是没有收货地址
            // 返回一个空的地址id=0，这样前端则会提醒添加地址
            if (addressVo == null) {
                addressVo = new AddressVo();
                addressVo.setId(0);
                addressId = 0;
            } else {
                addressId = addressVo.getId();
            }

        } else {
            checkedAddressR = addressFeignClient.query(userId, addressId);
            List<Map> checkedAddressMap = MapUtil.get((Map)checkedAddressR.get("page"),"list",List.class);
            if(checkedAddressMap.size()>0){
                addressVo = BeanUtil.mapToBean(checkedAddressMap.get(0), AddressVo.class,false);
            }
            // 如果null, 则报错
            if (addressVo == null) {
                return R.badArgumentValue();
            }
        }

        // 团购优惠
        BigDecimal grouponPrice = new BigDecimal(0.00);
        R grouponRulesR = groupOnFeignClient.queryById(grouponRulesId);
        GroupOnRulesVo groupOnVo = MapUtil.get(grouponRulesR, "grouponRules", GroupOnRulesVo.class);

        if (groupOnVo != null) {
            grouponPrice = groupOnVo.getGrouponDiscount();
        }

        // 商品价格
        List<CartDTO> checkedGoodsList = null;
        if (cartId == null || cartId.equals(0)) {
            checkedGoodsList = cartService.queryByUid(userId);
        } else {
            CartDTO cart = cartService.findById(cartId);
            if (cart == null) {
                return R.badArgumentValue();
            }
            checkedGoodsList = new ArrayList<>(1);
            checkedGoodsList.add(cart);
        }
        BigDecimal checkedGoodsPrice = new BigDecimal(0.00);
        for (CartDTO cart : checkedGoodsList) {
            //  只有当团购规格商品ID符合才进行团购优惠
            if (groupOnVo != null && groupOnVo.getGoodsId().equals(cart.getGoodsId())) {
                checkedGoodsPrice = checkedGoodsPrice.add(cart.getPrice().subtract(grouponPrice).multiply(new BigDecimal(cart.getNumber())));
            } else {
                checkedGoodsPrice = checkedGoodsPrice.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            }
        }
        // 计算优惠券可用情况
        BigDecimal tmpCouponPrice = new BigDecimal(0.00);
        Integer tmpCouponId = 0;
        Integer tmpUserCouponId = 0;
        int tmpCouponLength = 0;
        R couponUserListR = couponFeignClient.queryAll(userId);
        List<Map> couponUserMapList = MapUtil.get((Map) couponUserListR.get("page"), "list", List.class);
        for(Map couponUserMap : couponUserMapList){

            tmpUserCouponId = MapUtil.get(couponUserMap,"id",Integer.class);
            R couponR = couponFeignClient.checkCoupon(userId,MapUtil.get(couponUserMap,"couponId",Integer.class), tmpUserCouponId, checkedGoodsPrice);
            CouponVo couponVo = MapUtil.get(couponR, "coupon", CouponVo.class);
            if(couponVo == null){
                continue;
            }

            tmpCouponLength++;
            if(tmpCouponPrice.compareTo(couponVo.getDiscount()) == -1){
                tmpCouponPrice = couponVo.getDiscount();
                tmpCouponId = couponVo.getId();
            }
        }
        // 获取优惠券减免金额，优惠券可用数量
        int availableCouponLength = tmpCouponLength;
        BigDecimal couponPrice = new BigDecimal(0);
        // 这里存在三种情况
        // 1. 用户不想使用优惠券，则不处理
        // 2. 用户想自动使用优惠券，则选择合适优惠券
        // 3. 用户已选择优惠券，则测试优惠券是否合适
        if (couponId == null || couponId.equals(-1)){
            couponId = -1;
            userCouponId = -1;
        }
        else if (couponId.equals(0)) {
            couponPrice = tmpCouponPrice;
            couponId = tmpCouponId;
            userCouponId = tmpUserCouponId;
        }
        else {
            R couponR = couponFeignClient.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice);
            CouponVo couponVo = MapUtil.get(couponR, "coupon", CouponVo.class);
            // 用户选择的优惠券有问题，则选择合适优惠券，否则使用用户选择的优惠券
            if(couponVo == null){
                couponPrice = tmpCouponPrice;
                couponId = tmpCouponId;
                userCouponId = tmpUserCouponId;
            }
            else {
                couponPrice = couponVo.getDiscount();
            }
        }

        // 根据订单商品总价计算运费，满88则免运费，否则8元；
        BigDecimal freightPrice = new BigDecimal(0.00);

        if (checkedGoodsPrice.compareTo(MapUtil.get(systemConfigFeignClient.queryFreightLimit(),"freight_limit",BigDecimal.class)) < 0) {
            freightPrice = MapUtil.get(systemConfigFeignClient.queryFreight(),"freight",BigDecimal.class);
        }

        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = new BigDecimal(0.00);

        // 订单费用
        BigDecimal orderTotalPrice = checkedGoodsPrice.add(freightPrice).subtract(couponPrice).max(new BigDecimal(0.00));

        BigDecimal actualPrice = orderTotalPrice.subtract(integralPrice);

        Map<String, Object> data = new HashMap<>();
        data.put("addressId", addressId);
        data.put("couponId", couponId);
        data.put("userCouponId", userCouponId);
        data.put("cartId", cartId);
        data.put("grouponRulesId", grouponRulesId);
        data.put("grouponPrice", grouponPrice);
        data.put("checkedAddress", addressVo);
        data.put("availableCouponLength", availableCouponLength);
        data.put("goodsTotalPrice", checkedGoodsPrice);
        data.put("freightPrice", freightPrice);
        data.put("couponPrice", couponPrice);
        data.put("orderTotalPrice", orderTotalPrice);
        data.put("actualPrice", actualPrice);
        data.put("checkedGoodsList", checkedGoodsList);
        return R.ok().put("data",data);
    }

    /**
     * 购物车商品货品勾选状态
     * <p>
     * 如果原来没有勾选，则设置勾选状态；如果商品已经勾选，则设置非勾选状态。
     *
     * @param userId 用户ID
     * @param body   购物车商品信息， { productIds: xxx, isChecked: 1/0 }
     * @return 购物车信息
     */
    @PostMapping("checked")
    @ApiImplicitParams({@ApiImplicitParam(name = "userId", value = "X-Litemall-Token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.", paramType = "header", required = true, dataType = "String")
            , @ApiImplicitParam(name = "body", value = "{ \"productIds\": \"xxx\", \"isChecked\": \"1/0\"}", required = true, paramType = "body", dataType = "String")})
    public Object checked(@LoginUser Integer userId, @RequestBody String body) {
//        userId = 4;
        if (userId == null) {
            return R.unlogin();
        }
        if (body == null) {
            return R.badArgument();
        }

        List<Integer> productIds = JacksonUtil.parseIntegerList(body, "productIds");
        if (productIds == null) {
            return R.badArgument();
        }

        Integer checkValue = JacksonUtil.parseInteger(body, "isChecked");
        if (checkValue == null) {
            return R.badArgument();
        }
        Boolean isChecked = (checkValue == 1);

        cartService.updateCheck(userId, productIds, isChecked);
        return index(userId);
    }
    /**
     * 购物车商品货品数量
     * <p>
     * 如果用户没有登录，则返回空数据。
     *
     * @param userId 用户ID
     * @return 购物车商品货品数量
     */
    @GetMapping("goodscount")
    public Object goodscount(@LoginUser Integer userId) {
        if (userId == null) {
            return R.unlogin();
        }

        int goodsCount = 0;
        List<CartDTO> cartList = cartService.queryByUid(userId);
        for (CartDTO cart : cartList) {
            goodsCount += cart.getNumber();
        }
        return R.ok().put("data",goodsCount);
    }
}
